#include <cstdio>

#include <sstream>

#include "RequestHandler.h"

#include "ClientManager.h"
#include "Config.h"
#include "ConfigManager.h"
#include "ErrorCode.h"

#include "utils.h"

#include "debug.h"

using namespace session_mgr;

session_mgr::RequestHandler::RequestHandler(session_mgr::ConfigManager* configManager):
responseCode(0),
responseBuffer(),
config(),
socket(NULL),
configManager(configManager),
clientManager(),
finished(false),
error(false)
{
}

void session_mgr::RequestHandler::setSocket(cbsocket::DefaultCallback* socket)
{
    this->socket = socket;
}

void session_mgr::RequestHandler::pushLine(const std::string& line)
{
    debug("Got line with %zu bytes.\n", (size_t)line.size());
    
    if(finished)
        return;
    
    if(line.empty())
        requestFinish();
    else
        parseLine(line);
}

void session_mgr::RequestHandler::parseLine(const std::string& line)
{
    if(error)
        return;
    
    std::string::size_type eqPos = line.find('=');
    
    if(eqPos == line.npos)
        response(Error_Invalid, "Usage: key=value");
    else
    {
        std::string const& key = line.substr(0, eqPos);
        std::string const& value = line.substr(eqPos + 1);
        
        if(key == "config")
        {
            config = configManager->getGenerator(value);
            if(!config)
                response(Error_Unable, "Config \"" + value + "\" is not available");
        }
        else if(!config)
            response(Error_Invalid, "First option must be \"config\"");
        else
        {
            if(!config->hasOption(key))
                response(Error_Unable, "Unable to handle option \"" + key + "\"");
            else if( !config->setOption(key, value) )
                response(Error_Invalid, "Usage: " + key + "=" + config->getFormat(key));
        }
    }
}

void session_mgr::RequestHandler::requestFinish()
{
    using namespace std;
    
    finished = true;
    
    if(!error)
    {
        std::string errMsg;
        
        if(!config->ready(&errMsg))
            response(Error_Invalid, errMsg);
        else
        {
            vector<ClientConnection> const& clients = getConfig().getClients();
            clientManager.reset(new ClientManager(clients.data(), clients.size()));
            
            std::string const& configFile = config->generateConfig
            (clientManager->getConnections().data(),
             clientManager->getConnections().size()
            );
            
            ostringstream len;
            len << configFile.size() << endl;
            len << configFile;
            
            response(Error_OK, len.str());
        }
    }
    responseFinish();
}

void session_mgr::RequestHandler::response(int code, const std::string& message)
{
    if(responseCode != 0 || !responseBuffer.empty())
        debug("Response overlapped.\n");
    
    responseCode = code;
    responseBuffer = message;
    if(code != Error_OK)
        error = true;
}

void session_mgr::RequestHandler::responseFinish()
{
    std::ostringstream msg;
    msg << responseCode << std::endl;
    msg << responseBuffer << std::endl;
    socket->write(msg.str().data(), msg.str().size());
}
